﻿namespace Nomo.UnityEditorModule
{
    [UnityEditor.CustomEditor(typeof(UnityCoreModule.Timer))]
    internal sealed class TimerEditor : UnityEditor.Editor
    {
        private const float                          LabelAndValueWidth = 80F;
        private const float                          ButtonWidth        = 40F;
        private       UnityCoreModule.Timer          _timer;
        private       UnityEditor.SerializedProperty _timing;
        private       UnityEditor.SerializedProperty _realtime;
        private       UnityEditor.SerializedProperty _loopTime;
        private       UnityEditor.SerializedProperty _from;
        private       UnityEditor.SerializedProperty _to;
        private       UnityEditor.SerializedProperty _time;
        private       UnityEditor.SerializedProperty _progress;
        private       UnityEditor.SerializedProperty _completed;
        private       UnityEditor.SerializedProperty _timeChanged;
        private       UnityEditor.SerializedProperty _secondChanged;
        private       UnityEditor.SerializedProperty _progressChanged;
        private       UnityEngine.GUIContent         _timingGUIContent;
        private       UnityEngine.GUIContent         _realtimeGUIContent;
        private       UnityEngine.GUIContent         _loopTimeGUIContent;
        private       UnityEngine.GUIContent         _fromGUIContent;
        private       UnityEngine.GUIContent         _toGUIContent;
        private       UnityEngine.GUIContent         _setToNegativeInfinityGUIContent;
        private       UnityEngine.GUIContent         _setToPositiveInfinityGUIContent;
        private       UnityEngine.GUIContent         _timeGUIContent;
        private       UnityEngine.GUIContent         _setTimeFromGUIContent;
        private       UnityEngine.GUIContent         _setTimeToGUIContent;
        private       UnityEngine.GUIContent         _progressGUIContent;

        private void OnEnable()
        {
            _timer                           = serializedObject.targetObject as UnityCoreModule.Timer;
            _timing                          = serializedObject.FindProperty("timing");
            _realtime                        = serializedObject.FindProperty("realtime");
            _loopTime                        = serializedObject.FindProperty("loopTime");
            _from                            = serializedObject.FindProperty("from");
            _to                              = serializedObject.FindProperty("to");
            _time                            = serializedObject.FindProperty("time");
            _progress                        = serializedObject.FindProperty("progress");
            _completed                       = serializedObject.FindProperty("completed");
            _timeChanged                     = serializedObject.FindProperty("timeChanged");
            _secondChanged                   = serializedObject.FindProperty("secondChanged");
            _progressChanged                 = serializedObject.FindProperty("progressChanged");
            _timingGUIContent                = new UnityEngine.GUIContent("Timing",   "正在计时吗？");
            _realtimeGUIContent              = new UnityEngine.GUIContent("Realtime", "是否使用真实时间来计时？");
            _loopTimeGUIContent              = new UnityEngine.GUIContent("LoopTime", "循环次数");
            _fromGUIContent                  = new UnityEngine.GUIContent("From",     "计时起点");
            _toGUIContent                    = new UnityEngine.GUIContent("To",       "计时终点");
            _setToNegativeInfinityGUIContent = new UnityEngine.GUIContent("-∞",       "将计时终点设为负无穷大");
            _setToPositiveInfinityGUIContent = new UnityEngine.GUIContent("+∞",       "将计时终点设为正无穷大");
            _timeGUIContent                  = new UnityEngine.GUIContent("Time",     "当前时间");
            _setTimeFromGUIContent           = new UnityEngine.GUIContent("↩",        "将当前时间设为计时起点");
            _setTimeToGUIContent             = new UnityEngine.GUIContent("↪",        "将当前时间设为计时终点");
            _progressGUIContent              = new UnityEngine.GUIContent("Progress", "计时进度");
        }

        public override void OnInspectorGUI()
        {
            serializedObject.Update();

            #region row 1

            UnityEditor.EditorGUILayout.PropertyField(_timing, _timingGUIContent);

            #endregion

            #region row 2

            UnityEditor.EditorGUILayout.PropertyField(_realtime, _realtimeGUIContent);

            #endregion

            #region row 3

            UnityEditor.EditorGUILayout.PropertyField(_loopTime, _loopTimeGUIContent);

            #endregion

            #region row 4

            var r = UnityEditor.EditorGUILayout.GetControlRect();

            var setToPositiveInfinityButtonRect = r;
            setToPositiveInfinityButtonRect.xMin = setToPositiveInfinityButtonRect.xMax - ButtonWidth;
            if (UnityEngine.GUI.Button(setToPositiveInfinityButtonRect, _setToPositiveInfinityGUIContent, UnityEditor.EditorStyles.miniButtonRight))
            {
                _timer.To            = float.PositiveInfinity;
                _to.floatValue       = _timer.To;
                _time.floatValue     = _timer.Time;
                _progress.floatValue = _timer.Progress;
                UnityEditor.EditorUtility.SetDirty(_timer);
            }

            var setToNegativeInfinityButtonRect = r;
            setToNegativeInfinityButtonRect.xMax = setToPositiveInfinityButtonRect.xMin;
            setToNegativeInfinityButtonRect.xMin = setToNegativeInfinityButtonRect.xMax - ButtonWidth;
            if (UnityEngine.GUI.Button(setToNegativeInfinityButtonRect, _setToNegativeInfinityGUIContent, UnityEditor.EditorStyles.miniButtonLeft))
            {
                _timer.To            = float.NegativeInfinity;
                _to.floatValue       = _timer.To;
                _time.floatValue     = _timer.Time;
                _progress.floatValue = _timer.Progress;
                UnityEditor.EditorUtility.SetDirty(_timer);
            }

            #endregion

            #region row 5

            r = UnityEditor.EditorGUILayout.GetControlRect();

            var fromLabelRect = r;
            fromLabelRect.xMax = fromLabelRect.xMin + LabelAndValueWidth;
            UnityEditor.EditorGUI.LabelField(fromLabelRect, _fromGUIContent);

            var toLabelRect = r;
            toLabelRect.xMin = toLabelRect.xMax - LabelAndValueWidth;
            UnityEditor.EditorGUI.LabelField(toLabelRect, _toGUIContent);

            #endregion

            #region row 6

            r = UnityEditor.EditorGUILayout.GetControlRect();

            var fromValueRect = r;
            fromValueRect.xMax = fromValueRect.xMin + LabelAndValueWidth;
            UnityEditor.EditorGUI.BeginChangeCheck();
            var from = UnityEditor.EditorGUI.FloatField(fromValueRect, _from.floatValue);
            if (UnityEditor.EditorGUI.EndChangeCheck())
            {
                _timer.From          = from;
                _from.floatValue     = _timer.From;
                _time.floatValue     = _timer.Time;
                _progress.floatValue = _timer.Progress;
                UnityEditor.EditorUtility.SetDirty(_timer);
            }

            var toValueRect = r;
            toValueRect.xMin = toValueRect.xMax - LabelAndValueWidth;
            UnityEditor.EditorGUI.BeginChangeCheck();
            var to = UnityEditor.EditorGUI.FloatField(toValueRect, _to.floatValue);
            if (UnityEditor.EditorGUI.EndChangeCheck())
            {
                _timer.To            = to;
                _to.floatValue       = _timer.To;
                _time.floatValue     = _timer.Time;
                _progress.floatValue = _timer.Progress;
                UnityEditor.EditorUtility.SetDirty(_timer);
            }

            #endregion

            #region row 7

            UnityEditor.EditorGUI.BeginChangeCheck();
            var time = UnityEngine.GUI.HorizontalSlider(UnityEditor.EditorGUILayout.GetControlRect(), _time.floatValue, _from.floatValue, _to.floatValue);
            if (UnityEditor.EditorGUI.EndChangeCheck())
            {
                _timer.Time          = time;
                _time.floatValue     = _timer.Time;
                _progress.floatValue = _timer.Progress;
                UnityEditor.EditorUtility.SetDirty(_timer);
            }

            #endregion

            #region row 8

            r = UnityEditor.EditorGUILayout.GetControlRect();

            var timeValueRect = r;
            timeValueRect.xMax = timeValueRect.xMin + LabelAndValueWidth;
            UnityEditor.EditorGUI.BeginChangeCheck();
            time = UnityEditor.EditorGUI.FloatField(timeValueRect, _time.floatValue);
            if (UnityEditor.EditorGUI.EndChangeCheck())
            {
                _timer.Time          = time;
                _time.floatValue     = _timer.Time;
                _progress.floatValue = _timer.Progress;
                UnityEditor.EditorUtility.SetDirty(_timer);
            }

            var progressValueRect = r;
            progressValueRect.xMin = progressValueRect.xMax - LabelAndValueWidth;
            UnityEditor.EditorGUI.BeginChangeCheck();
            var progress = UnityEditor.EditorGUI.FloatField(progressValueRect, _progress.floatValue);
            if (UnityEditor.EditorGUI.EndChangeCheck())
            {
                _timer.Progress      = progress;
                _time.floatValue     = _timer.Time;
                _progress.floatValue = _timer.Progress;
                UnityEditor.EditorUtility.SetDirty(_timer);
            }

            #endregion

            #region row 9

            r = UnityEditor.EditorGUILayout.GetControlRect();

            var timeLabelRect = r;
            timeLabelRect.xMax = timeLabelRect.xMin + LabelAndValueWidth;
            UnityEditor.EditorGUI.LabelField(timeLabelRect, _timeGUIContent);

            var progressLabelRect = r;
            progressLabelRect.xMin = progressLabelRect.xMax - LabelAndValueWidth;
            UnityEditor.EditorGUI.LabelField(progressLabelRect, _progressGUIContent);

            #endregion

            #region row 10

            r = UnityEditor.EditorGUILayout.GetControlRect();

            var setTimeFromButtonRect = r;
            setTimeFromButtonRect.xMax = setTimeFromButtonRect.xMin + ButtonWidth;
            if (UnityEngine.GUI.Button(setTimeFromButtonRect, _setTimeFromGUIContent, UnityEditor.EditorStyles.miniButtonLeft))
            {
                _timer.Time          = _from.floatValue;
                _time.floatValue     = _timer.Time;
                _progress.floatValue = _timer.Progress;
                UnityEditor.EditorUtility.SetDirty(_timer);
            }

            var setTimeToButtonRect = r;
            setTimeToButtonRect.xMin = setTimeFromButtonRect.xMax;
            setTimeToButtonRect.xMax = setTimeToButtonRect.xMin + ButtonWidth;
            if (UnityEngine.GUI.Button(setTimeToButtonRect, _setTimeToGUIContent, UnityEditor.EditorStyles.miniButtonRight))
            {
                _timer.Time          = _to.floatValue;
                _time.floatValue     = _timer.Time;
                _progress.floatValue = _timer.Progress;
                UnityEditor.EditorUtility.SetDirty(_timer);
            }

            #endregion

            UnityEditor.EditorGUILayout.Space();

            #region row 11

            UnityEditor.EditorGUILayout.PropertyField(_completed);

            #endregion

            #region row 12

            UnityEditor.EditorGUILayout.PropertyField(_timeChanged);

            #endregion

            #region row 13

            UnityEditor.EditorGUILayout.PropertyField(_secondChanged);

            #endregion

            #region row 14

            UnityEditor.EditorGUILayout.PropertyField(_progressChanged);

            #endregion

            serializedObject.ApplyModifiedProperties();
        }
    }
}
